/***
 * post请求解析
 */
import fs from 'fs';
import Path from 'path'


//处理数据
if(module) module.exports = toDealWith;
export default function toDealWith(stream:any,request:any=[],MAX = 1024*1024*1024*20){
    let size = 0;
    let type:string = stream.headers['content-type'] || "";
    // 解析出开始和结束
    let start = "2d2d"+Buffer.from(type.split("=")[1]).toString('hex');
    let end = start+"2d2d";

    let par:any = {parameter:{} ,temporary:{},state:true,file:[]}
    return new Promise((reserved,error)=>{
        let start = (data:Buffer)=>{
            size+=data.length;
            if(size > MAX){
                stream.removeListener("data",start);
                stream.removeListener("end",end);
                error(new Error("数据量超界"));
            }else{
                try{
                    pars(data.toString("hex"))
                }catch(err){
                    stream.removeListener("data",start);
                    stream.removeListener("end",end);
                    error(err); 
                }
            }
        };
        let end = ()=>{reserved(par)};
        stream.on("data",start)
        stream.on("end",end)
        stream.on("error",(err:Error)=>error(err))
    })

    function pars (data:string){
        //对数据进行分组
        data.split(new RegExp(`0d0a${start}0d0a|${start}0d0a|0d0a${end}0d0a`)).filter(e=>e).forEach(e=>{
            //判断有没有头数据
            if(e.includes("436f6e74656e742d446973706f736974696f6e")){
                let index:number = e.indexOf("0d0a0d0a");
                //把temporary中的数据保存好
                if(par.temporary.name){
                    par.parameter[par.temporary.name]=processData(par.temporary,request);par.temporary={};
                }
                //这是头部数据，解析属性
                par.temporary = pars_info(e.substring(0,index));
                //获取后面的所有数据
                //判断是文件还是普通变量
                if(par.temporary.filename){
                    let path = Path.join(process.cwd(),"/.temporary/",String(global.time()));
                    par.temporary.path=wrfile(path,e.substring(index+8))
                    par.temporary.delete=()=>{fs.unlinkSync(par.temporary.path);}
                    request.$file.push(par.temporary)
                }else
                    par.temporary.data = e.substring(index+8);
            }else{
                //不是头部数据,判断一下是不是文件
                if(par.temporary.filename){
                    wrfile(par.temporary.path,e,false);
                }else{
                    par.temporary.data+=e;
                }
            }
        })
        //判断是否结束
        if(data.endsWith(end+"0d0a") && par.temporary.name){
            par.parameter[par.temporary.name]=processData(par.temporary,request)
        }
    }    
}



//解析出参数，名称以及文件名称,如果有文件名称的话
function pars_info(str:string){
    // 如果数据中不包含Content-Disposition直接返回,这是一种保险措施
    if(!str.includes('436f6e74656e742d446973706f736974696f6e')){return {}}
    //把\r\n替换为;
    str = Buffer.from(str.replace(/0d0a/g,"3b20").replace(/22/g,""),'hex').toString();
    let obj = {};
    str.split("; ").forEach(e=>{
        let data = e.split(/: |=/g);
        obj[data[0]]=data[1];
    })
    return obj;
}


//把文件保存到临时目录
function wrfile(path:string,data:string|any,continuing=true):string|undefined{
    //变为二进制数据
    data = Buffer.from(data,"hex");
    //没有临时文件夹就创建
    if(!fs.existsSync(process.cwd()+'/.temporary')){fs.mkdirSync(process.cwd()+'/.temporary')}
    //如果continuing默认为true，那就代表这是新文件，直接创建
    if(continuing){
        // 如果文件存在就一直更换文件名
        while(fs.existsSync(path)){
            path = Path.join(process.cwd(),"/.temporary/",String(global.time()));
        }
        fs.writeFileSync(path,data,"binary");
    }else{
        //否则就在原有文件的情况下把数据追加进去
        fs.appendFileSync(path,data,"binary");
    }
    return path;
  
}

//解析数据
function processData(obj:any,request:any){
    if(obj.filename){
        //这是一个文件
        if(obj.path){
            return maxfile(obj,request)
        }
        return minfile(obj);
    }
    //这不是一个文件
    obj.data = Buffer.from(obj.data,'hex').toString();

    //是普通数据,这里需要使用json转化
    try{
        return JSON.parse(obj.data);
    }catch (e){
        return obj.data;
    }
}

//生成大文件对象
function maxfile(obj:any,request:any){
    obj.read=()=>fs.readFileSync(obj.path);
    obj.write=(pa:string)=>{
        return new Promise((ress,error)=>{
            // 判断文件是否存在
            if(!fs.existsSync(obj.path)){
                console.log("文件不存在",obj.path)
                ress(pa);return
            }
            let f = fs.createReadStream(obj.path)
            f.pipe(fs.createWriteStream(pa)).on("close",()=>{
                fs.unlinkSync(obj.path);
                ress(pa)
            })
            f.on("error",err=>{
                console.log(err.message);
                console.log(err);
                error(err);
            })
        })
    }
    obj.delete=()=>{
        if(fs.existsSync(obj.path))
           fs.unlinkSync(obj.path);
    }
    try{
        obj.size = fs.statSync(obj.path).size;
    }catch(err){
        console.log(err.message);
        console.log(err);
    }
    return obj;
}

// 小型文件不需要写入本地，写入本地就ok
function minfile(obj:any){
    obj.read=()=>Buffer.from(obj.data,'hex').toString('utf-8');
    obj.write=(pa:string)=>{
        fs.writeFileSync(pa,Buffer.from(obj.data,'hex'));
    }
    obj.delete=()=>{}
    obj.size = Buffer.byteLength(obj.data,'hex');
    return obj;
}